﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using WPFTrees.DataStructures;
using WPFTrees.Parser;
using System.IO;
using WPFTrees.Layouts;
using System.Diagnostics;
using Adorners_ResizingAdorner;
using System.Reflection;

namespace WPFTrees
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        const double maxDelta = 10;
        NTree<NewickNode> tree;
        List<Label> labels = new List<Label>();
        ILayout layout;
        Brush branchBrush = Brushes.Black;
        double scaleRatio = 1.0;
        bool bCircularLayout; 

        NTree<NewickNode> CurrentTree
        {
            get { return tree; }
            set
            {
                tree = value;
                ComputeLeaves();
                miTree.IsEnabled = true;
                if (layout == null)
                {
                    layout = new ClassicRadialLayout();                    
                }
                ICanUseBranchLengths layoutAsI = layout as ICanUseBranchLengths;
                miUseBranchLenghts.IsEnabled = (layoutAsI != null);
                miUseBranchLenghts.IsChecked = (layoutAsI != null);
                layout.Tree = value;                               
                canvas.Children.Clear();
                BuildTree(tree);
                RenderTree(tree);
            }
        }


        public MainWindow()
        {
            InitializeComponent();

            // standartni akce jsou resene pres commandy, proto treba 
            // v toolbaru neni poveseny handler na Print tlacitko
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, OpenOnExecute));
            this.CommandBindings.Add(new CommandBinding(NavigationCommands.Zoom, ZoomOnExecute));
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Print, PrintPreviewOnExecute));
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, FindOnExecute));
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, CloseOnExecute));
            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Help, HelpRequestedOnExecute));

            Binding b = new Binding("BackgroundColor");
            b.Source = DefaultSettings.Default;
            canvas.SetBinding(Canvas.BackgroundProperty, b);

            Binding b2 = new Binding("ShowLabels");
            b2.Source = DefaultSettings.Default;
            miShowLabels.SetBinding(MenuItem.IsCheckedProperty, b2);

            Binding b3 = new Binding("ShowInternalLabels");
            b3.Source = DefaultSettings.Default;
            miShowInternalLabels.SetBinding(MenuItem.IsCheckedProperty, b3);            
        }



        void label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Label label = sender as Label;
            label.CaptureMouse();
            rotatedLabel = label;
            if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
            {
                moveLabel = true;
                rotateLabel = false;
            }
            else
            {
                rotateLabel = true;
                moveLabel = false;
            }
            e.Handled = true;
        }

        void label_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Label label = sender as Label;
            label.ReleaseMouseCapture();
            rotatedLabel = null;
            rotateLabel = false;
            moveLabel = false;
            e.Handled = true;
        }    

        void label_MouseLeave(object sender, MouseEventArgs e)
        {
            Label l = sender as Label;
            l.BorderBrush = null;
        }

        void label_MouseEnter(object sender, MouseEventArgs e)
        {
            Label l = sender as Label;
            l.BorderBrush = Brushes.Blue;
        }         

        private void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (tree != null)
            {
                RenderTree(tree);
                //CenterTree();
            }           
        }            

        void ChangeLayout(ILayout newLayout)
        {
            ILayout oldLayout = layout;
            layout = newLayout;
            bool canUseBranchLenghts = layout is ICanUseBranchLengths;
            bool supportUnrooting = layout is ISupportUnrooting;            
            miUnroot.IsEnabled = miUnroot.IsChecked = supportUnrooting;
            bCircularLayout = supportUnrooting; // HACK, docasny reseni zakazu rotace labelu u circularnich layoutu
            miUseBranchLenghts.IsEnabled = (canUseBranchLenghts);
            miUseBranchLenghts.IsChecked = (canUseBranchLenghts);
            if (layout.BranchDrawer != oldLayout.BranchDrawer)
            {
                canvas.Children.Clear();
                BuildTree(tree);
            }
            RenderTree(tree);
            //CenterTree();
        }
       
        Point _rootPos;
        Point[] points = new Point[2];
        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (canvas.IsMouseCaptured)
            {
                // pohybuju kanvasem
                /*
                Mouse.GetIntermediatePoints(canvas, points);
                double deltaX = (points[0].X - points[1].X);
                double deltaY = (points[0].Y - points[1].Y);

                if (Math.Abs(deltaX) >= maxDelta)
                    deltaX = maxDelta * Math.Sign(deltaX);

                if (Math.Abs(deltaY) >= maxDelta)
                    deltaY = maxDelta * deltaY == 0 ? 0 : Math.Sign(deltaY);

                */
                //Debug.Assert(_rootPos.X >= 0);
                //Debug.Assert(_rootPos.Y >= 0);
                //layout.ExecuteLayout(canvas, tree.GetRoot());
                Point pt = Mouse.GetPosition(parentCanvas);
                Point pt2 = parentCanvas.TranslatePoint(pt, canvas);
                Canvas.SetLeft(dockPanel,pt.X-mousePosInCanvas.X);
                Canvas.SetTop(dockPanel, pt.Y - mousePosInCanvas.Y);
            }
            else
            {
                //statusBar1.Items[0] = string.Format("X:{0} Y:{1}", Mouse.GetPosition(canvas).X, Mouse.GetPosition(canvas).Y);               
            }

        }

        Point mousePosInCanvas;
        private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!canvas.IsMouseCaptured)
            {
                mousePosInCanvas = Mouse.GetPosition(dockPanel);
                //_rootPos.X = Canvas.GetLeft(CurrentTree.GetRoot().Value().VisualElement);
                //_rootPos.Y = Canvas.GetTop(CurrentTree.GetRoot().Value().VisualElement);

                //Debug.Assert(_rootPos.X >= 0);
                //Debug.Assert(_rootPos.Y >= 0);
                canvas.CaptureMouse();
            }
            this.Cursor = Cursors.Hand;
        }

        private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            canvas.ReleaseMouseCapture();
            this.Cursor = Cursors.Arrow;
        }

      

        ResizingAdorner adorner;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
#if DEBUG
            if (CurrentTree == null)
            {
                CurrentTree = Parser.NewickParser.Parse("(a:5,b:0.5,c:5.0,d:.5,e:5):2.4;");                
            }

            
            _rootPos = new Point(canvas.RenderSize.Width / 2.0, 0);

            Debug.Assert(_rootPos.X >= 0, "_rootPos.X >=0");
            Debug.Assert(_rootPos.Y >= 0, "_rootPos.Y >=0");

            RenderTree(CurrentTree);
#endif

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(parentCanvas);
            adorner = new ResizingAdorner(parentCanvas.Children[0]);
            
            adornerLayer.Add(adorner);

        }
     

        private void txtBoxFind_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                FindOnExecute(this, null);
            }
        }            

      
       
        private void canvas_MouseEnter(object sender, MouseEventArgs e)
        {
            canvas.Background = Brushes.LightBlue;
            statusBar1.Items[0] = "Click and drag around workspace.";
        }

        private void canvas_MouseLeave(object sender, MouseEventArgs e)
        {
            canvas.Background = DefaultSettings.Default.BackgroundColor;
            statusBar1.Items[0] = "";
        }
        bool moveLabel;

        private void parentCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (rotatedLabel == null) return;
            Label label = rotatedLabel;
            if (label.Tag ==null) //vnitrni popisek
                return;
            NewickNode node = label.Tag as NewickNode;
            double x = Canvas.GetLeft(node.VisualElement);
            double y = Canvas.GetTop(node.VisualElement);
            Point parentPt = new Point(x, y);
            Point mousePt = Mouse.GetPosition(canvas);

            if (rotateLabel)
            {
                // najdi vektor mezi listem kteremu popisek patri, a pozici kurzoru
              

                double betaRad = Math.Atan2((parentPt.X - mousePt.X), (parentPt.Y - mousePt.Y));
                double beta = betaRad * (180.0 / Math.PI);
                //double xAngle = 90 - beta;
                double alfa = 90-beta;
                Point translated = canvas.TranslatePoint(parentPt, label);                
                //RotateTransform rotate = new RotateTransform(alfa,translated.X,translated.Y);
                RotateTransform rotate = new RotateTransform(180+alfa, 0,0);
                label.RenderTransform = rotate;
                label.UpdateLayout();
                // otoc popisek ve smeru toho vektoru
            }
            else if (moveLabel)
            { 
                // posune popisek
                Point pt = Mouse.GetPosition(canvas);
                Canvas.SetLeft(label, pt.X-parentPt.X);
                Canvas.SetTop(label, pt.Y-parentPt.Y);                                
            }
        }
            
                     
    }
}
